﻿using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using PMS.Core.Configuration.CommonEnumConfigs;
using PMS.Core.Infrastructure;
using PMS.Data.Entities.Settings;
using PMS.Services.EntityServices.Common;
using PMS.Services.EntityServices.Localization;
using PMS.Services.EntityServices.Medias;
using PMS.Services.SharedKernel;
using PMS.Services.Utils;
using PMS.Web.Framework.Controllers;
using System;
using System.Collections.Generic;
using System.Text;

namespace PMS.Web.Controllers.Frontend.Common
{
    public partial class CommonController : BaseController
    {
        #region Fields

        //private readonly CaptchaSettings _captchaSettings;
        private readonly MediaSettings _mediaSettings;
        private readonly CommonSettings _commonSettings;
        //private readonly ICustomerActivityService _customerActivityService;
        private readonly IGenericAttributeService _genericAttributeService;
        private readonly ILanguageService _languageService;
        private readonly IPMSFileProvider _fileProvider;
        private readonly IStoreContext _storeContext;
        private readonly IWorkContext _workContext;
        private readonly IWebHelper _webHelper;

        private const int MAX_MEDIAFILE_UPLOAD = 8;
        #endregion

        #region Ctor

        public CommonController(MediaSettings mediaSettings,
            CommonSettings commonSettings,
            IGenericAttributeService genericAttributeService,
            ILanguageService languageService,
            IPMSFileProvider fileProvider,
            IStoreContext storeContext,
            IWorkContext workContext,
            IWebHelper webHelper)
        {
            _mediaSettings = mediaSettings;
            _commonSettings = commonSettings;
            _genericAttributeService = genericAttributeService;
            _languageService = languageService;
            _fileProvider = fileProvider;
            _storeContext = storeContext;
            _workContext = workContext;
            _webHelper = webHelper;
        }

        #endregion

        #region Utils
        /// <summary>
        /// Get robots.txt file
        /// </summary>
        /// <returns>Robots.txt file as string</returns>
        protected virtual string PrepareRobotsTextFile()
        {
            var sb = new StringBuilder();

            //if robots.custom.txt exists, let's use it instead of hard-coded data below
            var robotsFilePath = _fileProvider.Combine(_fileProvider.MapPath("~/"), "robots.custom.txt");
            if (_fileProvider.FileExists(robotsFilePath))
            {
                //the robots.txt file exists
                var robotsFileContent = _fileProvider.ReadAllText(robotsFilePath, Encoding.UTF8);
                sb.Append(robotsFileContent);
            }
            else
            {
                //doesn't exist. Let's generate it (default behavior)

                var disallowPaths = new List<string>
                {
                    "/admin",
                    "/backend",
                    "/bin/",
                    "/files/",
                    "/api/*",
                };
                var localizableDisallowPaths = new List<string>
                {
                    "/cart$",
                    "/changelanguage",
                    "/customer/avatar",
                    "/customer/activation",
                    "/customer/addresses",
                    "/customer/changepassword",
                    "/customer/checkusernameavailability",
                    "/customer/downloadableproducts",
                    "/customer/info",
                    "/search?",
                };

                const string newLine = "\r\n"; //Environment.NewLine
                sb.Append("User-agent: *");
                sb.Append(newLine);
               
                //host
                sb.AppendFormat("Host: {0}", _webHelper.GetStoreLocation());
                sb.Append(newLine);

                //usual paths
                foreach (var path in disallowPaths)
                {
                    sb.AppendFormat("Disallow: {0}", path);
                    sb.Append(newLine);
                }
                //localizable paths (without SEO code)
                foreach (var path in localizableDisallowPaths)
                {
                    sb.AppendFormat("Disallow: {0}", path);
                    sb.Append(newLine);
                }

                //URLs are localizable. Append SEO code
                foreach (var language in _languageService.GetAllLanguages(storeId: _storeContext.CurrentStore.Id))
                {
                    foreach (var path in localizableDisallowPaths)
                    {
                        sb.AppendFormat("Disallow: /{0}{1}", language.LanguageCode, path);
                        sb.Append(newLine);
                    }
                }

                //load and add robots.txt additions to the end of file.
                var robotsAdditionsFile = _fileProvider.Combine(_fileProvider.MapPath("~/"), "robots.additions.txt");
                if (_fileProvider.FileExists(robotsAdditionsFile))
                {
                    var robotsFileContent = _fileProvider.ReadAllText(robotsAdditionsFile, Encoding.UTF8);
                    sb.Append(robotsFileContent);
                }
            }

            return sb.ToString();
        }

        #endregion

        #region Methods

        //page not found
        public virtual IActionResult PageNotFound()
        {
            Response.StatusCode = 404;
            Response.ContentType = "text/html";
            ViewBag.WorkContext = _workContext;
            return View();
        }

        //Accessdenied  
        public IActionResult AccessDenied()
        {
            return View();
        }

        //ErrorPage
        public IActionResult ErrorPage(string errmsg = null, string returnurl = null)
        {
            if (!string.IsNullOrEmpty(errmsg) && errmsg.Equals("tokenexpired", StringComparison.OrdinalIgnoreCase))
                errmsg = "您的登录授权已过期,请重新登录";

            ViewBag.ErrMsg = errmsg;
            ViewBag.ReturnUrl = returnurl;
            return View();
        }
        public virtual IActionResult SetLanguage(int langid, string returnUrl = "")
        {
            var language = _languageService.GetLanguageById(langid);
            if (!language?.IsActive ?? false)
                language = _workContext.WorkingLanguage;

            //home page
            if (string.IsNullOrEmpty(returnUrl))
                returnUrl = Url.RouteUrl("Homepage");

            //remove current language code if it's already localized URL
            if (returnUrl.IsLocalizedUrl(Request.PathBase, true, out var _))
                returnUrl = returnUrl.RemoveLanguageSeoCodeFromUrl(Request.PathBase, true);

            //and add code of passed language
            returnUrl = returnUrl.AddLanguageSeoCodeToUrl(Request.PathBase, true, language);

            _workContext.WorkingLanguage = language;

            //prevent open redirection attack
            if (!Url.IsLocalUrl(returnUrl))
                returnUrl = Url.RouteUrl("Homepage");

            return Redirect(returnUrl);
        }

        //robots.txt file
        public virtual IActionResult RobotsTextFile()
        {
            var robotsFileContent = PrepareRobotsTextFile();
            return Content(robotsFileContent, "text/plain");
        }

        public virtual IActionResult GenericUrl()
        {
            //seems that no entity was found
            return InvokeHttp404();
        }

        public virtual IActionResult StoreClosed()
        {
            return View();
        }

        //helper method to redirect users. Workaround for GenericPathRoute class where we're not allowed to do it
        public virtual IActionResult InternalRedirect(string url, bool permanentRedirect)
        {
            //ensure it's invoked from our GenericPathRoute class
            if (HttpContext.Items["pms.RedirectFromGenericPathRoute"] == null ||
                !Convert.ToBoolean(HttpContext.Items["pms.RedirectFromGenericPathRoute"]))
            {
                url = Url.RouteUrl("Homepage");
                permanentRedirect = false;
            }

            //home page
            if (string.IsNullOrEmpty(url))
            {
                url = Url.RouteUrl("Homepage");
                permanentRedirect = false;
            }

            //prevent open redirection attack
            if (!Url.IsLocalUrl(url))
            {
                url = Url.RouteUrl("Homepage");
                permanentRedirect = false;
            }

            if (permanentRedirect)
                return RedirectPermanent(url);

            return Redirect(url);
        }

        /// <summary>
        /// 通用文件上传组件页，通过前端layui.layer包装成弹窗显示
        /// </summary>
        /// <param name="type">限制上传文件类型</param>
        /// <param name="max">限制上传文件数量</param>
        /// <returns></returns>
        public IActionResult MediaFileUploadPopup(MediaFileType type = MediaFileType.Image, MediaFileUseage useage = MediaFileUseage.Default, int max = 8)
        {
            string fileUploadExtNames = type == MediaFileType.Unknown
                ? "*"
                : string.Join(',', MimeTypesManager.Instance.GetSupportFileExtensionsByCategory(type));

            //按类型指定文件上传最大允许文件容量
            ViewBag.MaxUploadSize = type switch
            {
                MediaFileType.Audio => _mediaSettings.AudioMaximumSizeBytes,
                MediaFileType.Image => _mediaSettings.ImageMaximumSizeBytes,
                MediaFileType.TextFile => _mediaSettings.TxtFileMaximumSizeBytes,
                MediaFileType.Video => _mediaSettings.VideoMaximumSizeBytes,
                MediaFileType.ZipFile => _mediaSettings.ZipFileMaximumSizeBytes,
                _ => 3145728 //未指定上传文件类型时，设定统一上传文件大小为最小值 3M
            };
            //指定单次允许上传文件数量
            ViewBag.MaxUploadCount = Math.Min(max, MAX_MEDIAFILE_UPLOAD);
            //指定允许上传文件类型，即文件扩展名
            ViewBag.UploadExtNames = fileUploadExtNames;
            //指定上传文件的分类描述
            ViewBag.Useage = Enum.ToObject(typeof(MediaFileUseage), useage).ToString();
            return View();
        }
        #endregion
    }
}
